package com.glp.work.flow.utils;

import com.glp.work.flow.constant.FLMsgEventEnum;
import com.glp.work.flow.listener.AssignerTaskHandler;
import com.glp.work.flow.listener.GlobalExecutionHandler;
import com.glp.work.flow.listener.MiddleMessageHandler;
import com.glp.work.flow.workflow.plugin.flowable.constant.FlowConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 流程定义工具类
 *
 * @author pengjia
 * @version 2020年5月27日 下午8:16:28
 */
@Slf4j
public class BpmnModelUtils {

    private BpmnModelUtils() {
    }

    public static void defaultDynamicAddEventListener(BpmnModel bpmnModel) {
        {
            //初始化Message
            Message message = new Message();
            message.setId(FLMsgEventEnum.DEFAULT.getEvent());
            message.setName(FLMsgEventEnum.DEFAULT.getEvent());
            bpmnModel.addMessage(message);
        }
        Process process = bpmnModel.getMainProcess();
        globaExecHandlerInit(process);
        Collection<FlowElement> flowElements = process.getFlowElements();
        if (CollectionUtils.isNotEmpty(flowElements)) {
            {
                for (FlowElement flowElement : flowElements) {
                    if (flowElement instanceof StartEvent) {
                        startEventInit((StartEvent) flowElement);
                    } else if (flowElement instanceof UserTask) {
                        UserTask userTask = (UserTask) flowElement;
                        taskHandlerInit(userTask);
                    } else if (flowElement instanceof IntermediateCatchEvent) {
                        IntermediateCatchEvent intermediateCatchEvent = (IntermediateCatchEvent) flowElement;
                        middleMessageHandlerInit(intermediateCatchEvent);
                    } else if (flowElement instanceof EndEvent) {
                        endEventInit((EndEvent) flowElement);
                    }
                }
            }
        }
    }

    private static void endEventInit(EndEvent endEvent) {
        String name = endEvent.getName();
        if (StringUtils.isNoneBlank(name)) {
            endEvent.setName(name);
        } else {
            endEvent.setName(FlowConstant.OVER);
        }
    }

    private static void startEventInit(StartEvent startEvent) {
        String name = startEvent.getName();
        if (StringUtils.isNoneBlank(name)) {
            startEvent.setName(name);
        } else {
            startEvent.setName(FlowConstant.START);
        }
    }

    private static void globaExecHandlerInit(Process process) {
        log.info("初始化全局执行监听器...{}", process.getName());
        List<FlowableListener> execListeners = process.getExecutionListeners();
        if (CollectionUtils.isEmpty(execListeners)) {
            execListeners = new ArrayList<>();
            execListeners.add(getDefaultExecListener(GlobalExecutionHandler.EVENTNAME_START, GlobalExecutionHandler.GLOBAL_LISTENER_IMPL));
            execListeners.add(getDefaultExecListener(GlobalExecutionHandler.EVENTNAME_TAKE, GlobalExecutionHandler.GLOBAL_LISTENER_IMPL));
            execListeners.add(getDefaultExecListener(GlobalExecutionHandler.EVENTNAME_END, GlobalExecutionHandler.GLOBAL_LISTENER_IMPL));
        } else {
            List<String> idList = execListeners.stream().map(fl -> fl.getEvent() + fl.getImplementation()).collect(Collectors.toList());
            if (!idList.contains(GlobalExecutionHandler.EVENTNAME_START + GlobalExecutionHandler.GLOBAL_LISTENER_IMPL)) {
                execListeners.add(getDefaultExecListener(GlobalExecutionHandler.EVENTNAME_START, GlobalExecutionHandler.GLOBAL_LISTENER_IMPL));
            }
            if (!idList.contains(GlobalExecutionHandler.EVENTNAME_TAKE + GlobalExecutionHandler.GLOBAL_LISTENER_IMPL)) {
                execListeners.add(getDefaultExecListener(GlobalExecutionHandler.EVENTNAME_TAKE, GlobalExecutionHandler.GLOBAL_LISTENER_IMPL));
            }
            if (!idList.contains(GlobalExecutionHandler.EVENTNAME_END + GlobalExecutionHandler.GLOBAL_LISTENER_IMPL)) {
                execListeners.add(getDefaultExecListener(GlobalExecutionHandler.EVENTNAME_END, GlobalExecutionHandler.GLOBAL_LISTENER_IMPL));
            }
        }
        process.setExecutionListeners(execListeners);

    }

    private static void middleMessageHandlerInit(IntermediateCatchEvent intermediateCatchEvent) {
        {
            log.info("初始化中间消息组件EVENT...{}", intermediateCatchEvent.getName());
            List<EventDefinition> eventList = intermediateCatchEvent.getEventDefinitions();
            if (!CollectionUtils.isEmpty(eventList)) {
                for (EventDefinition event : eventList) {
                    if (event instanceof MessageEventDefinition) {
                        String ref = ((MessageEventDefinition) event).getMessageRef();
                        if (StringUtils.isBlank(ref)) {
                            ((MessageEventDefinition) event).setMessageRef(FLMsgEventEnum.DEFAULT.getEvent());
                        }
                    }
                }
                List<String> messageRefs = eventList.stream().map((EventDefinition mapper) -> {
                    if (mapper instanceof MessageEventDefinition) {
                        return ((MessageEventDefinition) mapper).getMessageRef();
                    }
                    return "";
                }).collect(Collectors.toList());
                if (!messageRefs.contains(FLMsgEventEnum.DEFAULT.getEvent())) {
                    MessageEventDefinition messageEvent = new MessageEventDefinition();
                    messageEvent.setMessageRef(FLMsgEventEnum.DEFAULT.getEvent());
                    intermediateCatchEvent.addEventDefinition(messageEvent);
                }
            } else {
                MessageEventDefinition messageEvent = new MessageEventDefinition();
                messageEvent.setMessageRef(FLMsgEventEnum.DEFAULT.getEvent());
                intermediateCatchEvent.addEventDefinition(messageEvent);
            }
        }
        {
            log.info("初始化中间消息组件ExecutionListener...{}", intermediateCatchEvent.getName());
            List<FlowableListener> execListeners = intermediateCatchEvent.getExecutionListeners();
            if (CollectionUtils.isEmpty(execListeners)) {
                execListeners = new ArrayList<>();
                execListeners.add(getDefaultExecListener(MiddleMessageHandler.EVENTNAME_START, MiddleMessageHandler.MIDDEL_MESSAGE_LISTENER_IMPL));
                execListeners.add(getDefaultExecListener(MiddleMessageHandler.EVENTNAME_END, MiddleMessageHandler.MIDDEL_MESSAGE_LISTENER_IMPL));
            } else {
                List<String> idList = execListeners.stream().map(fl -> fl.getEvent() + fl.getImplementation()).collect(Collectors.toList());

                if (!idList.contains(GlobalExecutionHandler.EVENTNAME_START + MiddleMessageHandler.MIDDEL_MESSAGE_LISTENER_IMPL)) {
                    execListeners.add(getDefaultExecListener(MiddleMessageHandler.EVENTNAME_START, MiddleMessageHandler.MIDDEL_MESSAGE_LISTENER_IMPL));
                }

                if (!idList.contains(GlobalExecutionHandler.EVENTNAME_END + MiddleMessageHandler.MIDDEL_MESSAGE_LISTENER_IMPL)) {
                    execListeners.add(getDefaultExecListener(MiddleMessageHandler.EVENTNAME_END, MiddleMessageHandler.MIDDEL_MESSAGE_LISTENER_IMPL));
                }
            }
            intermediateCatchEvent.setExecutionListeners(execListeners);
        }
    }

    private static void taskHandlerInit(UserTask userTask) {
        {
            log.info("初始化任务监听器组件...{}", userTask.getName());
            List<FlowableListener> taskListeners = userTask.getTaskListeners();
            if (CollectionUtils.isEmpty(taskListeners)) {
                taskListeners = new ArrayList<>();
                taskListeners.add(getTaskAssignerListener(AssignerTaskHandler.EVENTNAME_CREATE, AssignerTaskHandler.ASSIGNER_TASK_LISTENER_IMPL));
                taskListeners.add(getTaskAssignerListener(AssignerTaskHandler.EVENTNAME_COMPLETE, AssignerTaskHandler.ASSIGNER_TASK_LISTENER_IMPL));
            } else {
                List<String> idList = taskListeners.stream().map(fl -> fl.getEvent() + fl.getImplementation()).collect(Collectors.toList());
                if (!idList.contains(AssignerTaskHandler.EVENTNAME_CREATE + AssignerTaskHandler.ASSIGNER_TASK_LISTENER_IMPL)) {
                    taskListeners.add(getTaskAssignerListener(AssignerTaskHandler.EVENTNAME_CREATE, AssignerTaskHandler.ASSIGNER_TASK_LISTENER_IMPL));
                }
                if (!idList.contains(AssignerTaskHandler.EVENTNAME_COMPLETE + AssignerTaskHandler.ASSIGNER_TASK_LISTENER_IMPL)) {
                    taskListeners.add(getTaskAssignerListener(AssignerTaskHandler.EVENTNAME_COMPLETE, AssignerTaskHandler.ASSIGNER_TASK_LISTENER_IMPL));
                }
            }
            userTask.setTaskListeners(taskListeners);
        }
        {
            log.info("初始化会签组件...{}", userTask.getName());
            if (userTask.getName().contains(FlowConstant.COUNTERSIGN_NAME)) {
                MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = userTask.getLoopCharacteristics();
                if (multiInstanceLoopCharacteristics == null) {
                    multiInstanceLoopCharacteristics = new MultiInstanceLoopCharacteristics();
                }
                multiInstanceLoopCharacteristics.setSequential(false);
                multiInstanceLoopCharacteristics.setInputDataItem("${mutiInstanceHandler.getTaskUsers(execution)}");
                multiInstanceLoopCharacteristics.setElementVariable("assignee");
                if (StringUtils.isBlank(multiInstanceLoopCharacteristics.getCompletionCondition())) {
                    multiInstanceLoopCharacteristics.setCompletionCondition("${mutiInstanceHandler.getComplete(execution)}");
                }
//				multiInstanceLoopCharacteristics.setLoopCardinality("${assigneeList.size()}");
                userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
            }
        }

    }

    /**
     * 任务分配监听器
     *
     * @return
     */
    private static FlowableListener getTaskAssignerListener(String event, String impl) {
        FlowableListener listener = new FlowableListener();
        listener.setEvent(event);
        listener.setImplementation(impl);
        listener.setImplementationType("class");
        return listener;
    }

    private static FlowableListener getDefaultExecListener(String event, String impl) {
        FlowableListener listener = new FlowableListener();
        listener.setEvent(event);
        listener.setImplementation(impl);
        listener.setImplementationType("class");
        return listener;
    }

}
